package cn.legend.travel.passport.service.impl;


import cn.legend.travel.common.enumerator.ServiceCode;
import cn.legend.travel.common.exception.ServiceException;
import cn.legend.travel.common.pojo.authentication.CurrentPrincipal;
import cn.legend.travel.common.pojo.po.UserStatePO;
import cn.legend.travel.passport.dao.cache.IUserCacheRepository;
import cn.legend.travel.passport.dao.persist.repository.IUserRepository;
import cn.legend.travel.passport.pojo.entity.User;
import cn.legend.travel.passport.pojo.param.UserLoginInfoParam;
import cn.legend.travel.passport.pojo.param.UserRegInfoParam;
import cn.legend.travel.passport.pojo.vo.UserLoginInfoVO;
import cn.legend.travel.passport.pojo.vo.UserLoginResultVO;
import cn.legend.travel.passport.service.IUserService;

import cn.legend.travel.passport.util.SmsService;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Service
public class UserServiceImpl implements IUserService {
    @Value("${travel.jwt.secret-key}")
    private String secretKey;
    @Autowired
    private IUserRepository iUserRepository;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private IUserCacheRepository iUserCacheRepository;

    @Override
    public UserLoginResultVO login(UserLoginInfoParam userLoginInfoParam, HttpServletRequest request) {
        // 从参数中取出username
        String username= userLoginInfoParam.getUsername();
        // 调用repository，根据用户名查询用户数据
        UserLoginInfoVO loginInfoByUsername =
                iUserRepository.getLoginInfoByUsername(username);
        // 判断查询结果是否为null
        if (loginInfoByUsername==null){
            // 是：抛出异常（用户名不存在）
            String message="登录失败，用户名错误";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED,message);
        }

        // 判断查询结果中的账号状态（enable）是否“不处于”正常状态
        // 是：抛出异常（账号状态异常）
        if (loginInfoByUsername.getState()==0){
            String message="登录失败,账号状态异常";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED_DISABLED,message);
        }

        // 判断查询结果中的密码与参数中的密码是否“不匹配”
        String password=userLoginInfoParam.getPassword();
        if (!passwordEncoder.matches(password, loginInfoByUsername.getPassword())){
            String message="登录失败，密码错误";
            throw new ServiceException(ServiceCode.ERROR_CONFLICT,message);
        }
//        System.out.println("登录成功！");
        return getTokenResult(loginInfoByUsername, request);
    }

    @Override
    public UserLoginResultVO loginByPhone(String phone, HttpServletRequest request) {
        UserLoginInfoVO loginInfoByUsername = null;
        // 判断查询结果为null,则注册该手机号
        if (iUserRepository.getLoginInfoByUsername(phone)==null){
            User user=new User();
            user.setUsername(phone);
            user.setPassword("");
            user.setPhone(phone);
            user.setAvatar("http://localhost:50200/image.jpg");
            int rows = iUserRepository.insertUser(user);
            if (rows != 1){
                String message = "注册失败，服务器繁忙，请稍后再尝试！";
                throw new ServiceException(ServiceCode.ERROR_INSERT, message);
            }
        }
        // 调用repository，根据(账号)手机号查询用户数据
        loginInfoByUsername=iUserRepository.getLoginInfoByUsername(phone);
        // 判断查询结果中的账号状态（enable）是否“不处于”正常状态
        // 是：抛出异常（账号状态异常）
        if (loginInfoByUsername.getState()==0){
            String message="登录失败,账号状态异常";
            throw new ServiceException(ServiceCode.ERROR_UNAUTHORIZED_DISABLED,message);
        }

        return getTokenResult(loginInfoByUsername, request);
    }

    @Override
    public void reg(UserRegInfoParam userRegInfoParam) {
        UserLoginInfoVO loginInfoVO =
                iUserRepository.getLoginInfoByUsername(userRegInfoParam.getUsername());
        if (loginInfoVO!=null){
            String message="该用户已存在，请重新输入！";
            throw new ServiceException(ServiceCode.ERROR_CONFLICT,message);
        }
        User user=new User();
        BeanUtils.copyProperties(userRegInfoParam,user);
        user.setPassword(passwordEncoder.encode(userRegInfoParam.getPassword()));
        user.setPhone(userRegInfoParam.getPhone());
        user.setAvatar("http://localhost:50200/image.jpg");
        int rows = iUserRepository.insertUser(user);
        if (rows != 1){
            String message = "注册失败，服务器繁忙，请稍后再尝试！";
            throw new ServiceException(ServiceCode.ERROR_INSERT, message);
        }
    }

    @Override
    public void logout(CurrentPrincipal currentPrincipal) {
        iUserCacheRepository.deleteUserState(currentPrincipal.getId());
    }

    @Override
    public void send(String phone, String key) {
        SmsService.send(phone, key);
        iUserCacheRepository.saveVerifyCode(key,phone);
    }

    @Override
    public int compareCode(String phone,String preAuthCode) {
        String verifyCode = iUserCacheRepository.getVerifyCode(phone);
        //验证码不为空时，到后台进行比较，返回响应码，为1，提示请先获得验证码
        //为2，提示验证码错误
        //为3，验证码正确，无提示
        if(verifyCode==null){
            return 1;
        }else if(verifyCode.equals(preAuthCode)){
            return 3;
        }else{
            return 2;
        }
    }

    private UserLoginResultVO getTokenResult(UserLoginInfoVO loginInfoByUsername,HttpServletRequest request){
        UserStatePO userStatePO=new UserStatePO();
        userStatePO.setState(loginInfoByUsername.getState());
        iUserCacheRepository.saveUserState(loginInfoByUsername.getId(), userStatePO);

        Map<String,Object> claims=new HashMap<>();
        claims.put("id",loginInfoByUsername.getId());
        claims.put("username",loginInfoByUsername.getUsername());
        claims.put("remote_addr",request.getRemoteAddr());
        claims.put("user_agent",request.getHeader("User-Agent"));
        String jwt = Jwts.builder()
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                .setClaims(claims)
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();

        UserLoginResultVO resultVO=new UserLoginResultVO();
        resultVO.setId(loginInfoByUsername.getId());
        resultVO.setUsername(loginInfoByUsername.getUsername());
        resultVO.setAvatar(loginInfoByUsername.getAvatar());
        resultVO.setNickname(loginInfoByUsername.getNickname());
        resultVO.setToken(jwt);
        return resultVO;
    }

}
